#include "CSRMatrix.h"
#include "DecoLogger.h"
#include "mathlib.h"
#include "Utility.h"

void CSRMatrix::SetDim(int numGridX, int numGridY, int numGridZ)
{
	values.clear();
	columns.clear();
	rowIndex.clear();

	numX = numGridX;
	numY = numGridY;
	numZ = numGridZ;
	n = 0;
}

CSRMatrix::CSRMatrix() : n(0), numX(0), numY(0), numZ(0), isSymmetric(false)
{
	values.clear();
	columns.clear();
	rowIndex.clear();
}

CSRMatrix::CSRMatrix(int numGridX, int numGridY, int numGridZ) : n(0), numX(0), numY(0), numZ(0)
{
	values.clear();
	columns.clear();
	rowIndex.clear();
	SetDim(numGridX, numGridY, numGridZ);
}


CSRMatrix::~CSRMatrix()
{
	n = 0;
	values.clear();
	columns.clear();
	rowIndex.clear();
}

bool CSRMatrix::GetDiagonalElement(int i, int& index, double& value)
{
	return GetElement(i, i, index, value);
}

bool CSRMatrix::GetElement(int i, int j, int& index, double& value) 
{
	if (isSymmetric && i > j)
	{
		int tmp = i;
		i = j;
		j = tmp;
	}
	int rowStartIdx = rowIndex[i - 1]; 
	int rowEndIdx = rowIndex[i];

	for (int colIdx = rowStartIdx; colIdx < rowEndIdx; ++colIdx)
	{
		if (columns[colIdx] == j)
		{
			index = colIdx;
			value = values[colIdx];
			return true;
		}
	}
	return false;
}

void CSRMatrix::GetRow(int i, int& startIdx, int& numEntries) 
{
	startIdx = rowIndex[i - 1]; 
	int rowEndIdx = rowIndex[i];
	numEntries = rowEndIdx - startIdx;
}

void CSRMatrix::Transpose() 
{
	vector<double> newValues;
	vector<int> newColumns;
	vector<int> newRowIndex;

	bool sym = isSymmetric;

	isSymmetric = false;
	int idx;
	double value;
	newRowIndex.push_back(1);
	int colCounter = 1;

	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= n; ++j)
		{
			if (GetElement(j, i, idx, value))
			{
				newValues.push_back(value);
				newColumns.push_back(j);
				colCounter++;
			}
		}
		newRowIndex.push_back(colCounter);
	}
	assert(newValues.size() == values.size());
	assert(newColumns.size() == columns.size());
	assert(newRowIndex.size() == rowIndex.size());

	values = newValues;
	columns = newColumns;
	rowIndex = newRowIndex;
	isSymmetric = sym;
}

void CSRMatrix::ConvertFromFluidSparseMatrix(const FLuidSparseMatrix& m, bool bSymmetric)
{
	isSymmetric = bSymmetric;
	n = m.mDim;
	if (m.mDim != static_cast<int>(m.mRows.size()))
	{
		(*DecoLogger::GetSingleton()) << "Number of rows and dimension do not match when transfering from FluidSparseMatrix to CSRMatrix!\n";
		(*DecoLogger::GetSingleton()) << "m.mDim: " << m.mDim << "     m.mRows.size: " << static_cast<int>(m.mRows.size()) << "!\n";
		assert(0);
	}
	int numRows = static_cast<int>(m.mRows.size());
	for (int rowIt = 0; rowIt < numRows; ++rowIt)
	{
		if (rowIt == 0)
			rowIndex.push_back(1);

		const FluidSparseVector& row = m.mRowValues[rowIt];

		int totalLength = rowIndex[rowIndex.size() - 1] - 1;
		
		int numCols = static_cast<int>(row.mValues.size());
		int columnCounter = 0;

		for (int colIt = 0; colIt < numCols; ++colIt)
		{
			Index3 index3D = row.mIndices[colIt];
			int index1D = m.mIndex3Dto1DMap[index3D.m_i][index3D.m_j][index3D.m_k];//index3Dto1DMap[index3D.m_i][index3D.m_j][index3D.m_k];
			if (bSymmetric && index1D > rowIt)
			{
				continue;
			}
			assert(index1D != -1);
			double value = row.mValues[colIt];
			
			int sortIt;
			for (sortIt = totalLength; sortIt < static_cast<int>(columns.size()); ++sortIt)
			{
				if (columns[sortIt] > index1D)
					break;
			}
			//sortIt--;
			columns.insert(columns.begin() + sortIt, index1D + 1);
			values.insert(values.begin() + sortIt, value);
			columnCounter++;
		}
		rowIndex.push_back(totalLength + columnCounter + 1);

	}

}



